package com.ark.frigate.mybatis.common;

import com.ark.frigate.mybatis.config.StrategyConfig;
import com.ark.frigate.mybatis.utils.ColumnType;
import com.ark.frigate.mybatis.utils.FileUtils;
import com.ark.frigate.mybatis.utils.TempBatisUtils;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

/**
 * 对文件创建的抽象, 用于生成实体类 和 映射 XML 文件
 *
 * @author WeiLong
 */
public class CreateFileHandle {

    private static Logger logger = LoggerFactory.getLogger(CreateFileHandle.class);

    protected StrategyConfig strategyConfig;

    protected String entityClass;

    protected String xmlMapper;

    public CreateFileHandle(String entityClass, String xmlMapper) {

        if (StringUtils.isNotBlank(entityClass)) {
            this.entityClass = entityClass;
        }
        if (StringUtils.isNotBlank(xmlMapper)) {
            this.xmlMapper = xmlMapper;
        }
    }

    /**
     * 生成实体类
     *
     * @param columns      列
     * @param types        类型
     * @param comments     备注
     * @param tableComment 表名
     * @param beanName     实体名
     * @throws IOException IO异常
     */
    public void buildEntityBean(List<String> columns, List<String> types, List<String> comments, String tableComment,
                                String beanName) throws IOException {

        tableComment = StringUtils.isBlank(tableComment) ? "Please add the class description" : tableComment;
        Map<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("BeanPackage", strategyConfig.getBeanPackage());
        paramMap.put("TableComment", tableComment);
        paramMap.put("ImportAnnotation", strategyConfig.getImportAnnotation());
        paramMap.put("WriteAnnotation", strategyConfig.getWriteAnnotation());
        paramMap.put("ClassName", beanName);
        paramMap.put("Author", strategyConfig.getAuthor());

        // 属性
        StringBuilder javaFiled = new StringBuilder("\n");
        int size = columns.size();
        for (int i = 0; i < size; i++) {
            javaFiled.append("\t/**\n");
            javaFiled.append("\t * " + comments.get(i) + "\n");
            javaFiled.append("\t **/\n");
            javaFiled.append("\tprivate " + ColumnType.processType(types.get(i)) + " "
                    + ColumnType.processField(columns.get(i)) + ";\n\n");
        }
        paramMap.put("JavaFiled", javaFiled.toString());
        // 生成get 和 set方法
        StringBuilder javaMethod = new StringBuilder("\n");
        String tempField = null;
        String subTempField = null;
        String tempType = null;
        for (int i = 0; i < size; i++) {
            tempType = ColumnType.processType(types.get(i));
            subTempField = ColumnType.processField(columns.get(i));
            tempField = subTempField.substring(0, 1).toUpperCase() + subTempField.substring(1);
            javaMethod.append("\tpublic void set" + tempField + "(" + tempType + " " + subTempField + ") {\n");
            javaMethod.append("\t\tthis." + subTempField + " = " + subTempField + ";\n");
            javaMethod.append("\t}\n\n");
            javaMethod.append("\tpublic " + tempType + " get" + tempField + "() {\n");
            javaMethod.append("\t\treturn this." + subTempField + ";\n");
            javaMethod.append("\t}\n\n");
        }

        if (strategyConfig.isUseLombok()) {
            paramMap.put("ImportAnnotation", strategyConfig.getImportAnnotation() + "\nimport lombok.Data;");
            paramMap.put("WriteAnnotation", strategyConfig.getWriteAnnotation() + "\n@Data");
            paramMap.put("JavaMethod", StringUtils.EMPTY);
        } else {
            paramMap.put("JavaMethod", javaMethod.toString());
        }

        InputStream javabeanIs = this.getClass().getClassLoader().getResourceAsStream(entityClass);
        // 读取模板
        String content = TempBatisUtils.readToTemplate(javabeanIs, paramMap);
        // 新建一个文件
        File folder = new File(strategyConfig.getBeanPath());
        if (!folder.exists()) {
            boolean createFolder = folder.mkdirs();
            logger.info("文件创建结束，{}", createFolder);
        }
        File beanFile = new File(strategyConfig.getBeanPath(), beanName + ".java");
        // 写入文件
        FileUtils.writeContent(beanFile, content);
    }

    /**
     * 构建实体类映射XML文件
     *
     * @param columns    列
     * @param types      类型
     * @param tableName  表名
     * @param beanName   实体名称
     * @param mapperName 映射文件名称
     * @throws IOException IO异常
     */
    public void buildMapperXml(List<String> columns, List<String> types, String tableName, String beanName,
                               String mapperName, String daoName) throws IOException {

        Map<String, Object> paramMap = Maps.newHashMap();
        // 接口路径
        if (StringUtils.isNotBlank(daoName)) {
            paramMap.put("NameSpace", strategyConfig.getDaoPackage() + "." + daoName);
        } else {
            paramMap.put("NameSpace", strategyConfig.getBeanPackage() + "." + beanName);
        }
        // 对应实体类路径
        paramMap.put("BeanPath", strategyConfig.getBeanPackage() + "." + beanName);
        // 基本列映射
        paramMap.put("MapDefault", TempBatisUtils.appendResultMap(columns));
        // 条件语句映射
        paramMap.put("WhereSql", TempBatisUtils.appendWhere(columns));
        // 对应实体类定义
        paramMap.put("BeanMap", beanName);
        // 列定义
        paramMap.put("ColName", TempBatisUtils.appendCol(columns));
        // 主键
        paramMap.put("Key", columns.get(0));
        // 主键对应类属性
        paramMap.put("KeyField", ColumnType.processField(columns.get(0)));
        // 主键类型
        paramMap.put("KeyType", "java.lang." + ColumnType.processType(types.get(0)));
        // 表名称
        if (ColumnType.keyWords().contains(tableName)) {
            paramMap.put("TableName", ColumnType.KEY + tableName + ColumnType.KEY);
        } else {
            paramMap.put("TableName", tableName);
        }
        // 插入值
        paramMap.put("InsertVal", TempBatisUtils.appendInsertVal(columns));

        // 插入（匹配有值的字段）
        paramMap.put("InsertSelectCol", TempBatisUtils.appendInsertMatchCol(columns));
        paramMap.put("InsertSelectVal", TempBatisUtils.appendInsertMatchVal(columns));

        // 更新
        paramMap.put("UpdateSQL", TempBatisUtils.appendUpdateSql(columns));

        // 更新（匹配有值的字段）
        paramMap.put("UpdateSelectSQL", TempBatisUtils.appendUpdateMatchSql(columns));

        paramMap.put("Author", strategyConfig.getAuthor());

        InputStream interfaceClass = this.getClass().getClassLoader().getResourceAsStream(xmlMapper);

        // 读取模板 预备写入内容
        String content = TempBatisUtils.readToTemplate(interfaceClass, paramMap);
        // 新建一个文件
        File folder = new File(strategyConfig.getXmlPath());
        if (!folder.exists()) {
            boolean createFolder = folder.mkdirs();
            logger.info("文件创建结束，{}", createFolder);
        }
        File mapperXmlFile = new File(strategyConfig.getXmlPath(), mapperName + ".xml");
        // 将内容写入文件
        FileUtils.writeContent(mapperXmlFile, content);
    }

    public StrategyConfig getStrategyConfig() {
        return strategyConfig;
    }

    public void setStrategyConfig(StrategyConfig strategyConfig) {
        this.strategyConfig = strategyConfig;
    }
}
